﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using Ionic.Zip;
using TorchView.Game;
using System.Text.RegularExpressions;

namespace TorchView.GameContent.Data
{
    /// <summary>
    /// Helper class used to read files from the pak.zip
    /// </summary>
    public static class PakReader
    {
        private class PakReaderHelper
        {
            private ZipFile zipFile;
            public PakReaderHelper()
            {
                zipFile = new ZipFile(Torchlight.InstallDirectory + @"\Pak.zip");
            }

            /// <summary>
            /// Open a copy of the file in the pak
            /// </summary>
            /// <param name="relativePath"></param>
            /// <returns></returns>
            public Stream OpenFile(string relativePath)
            {
                if (zipFile != null)
                {
                    var entry = zipFile[relativePath];// zipFile.FirstOrDefault(z => string.Compare(z.FileName, relativePath, true) == 0);
                    if (entry != null)
                    {
                        var stream = entry.OpenReader();
                        byte[] buffer = new byte[(int)stream.Length];
                        stream.Read(buffer, 0, buffer.Length);
                        return new MemoryStream(buffer);
                    }
                }
                return null;
            }

            /// <summary>
            /// Get the listing of files in the pak
            /// </summary>
            /// <param name="path"></param>
            /// <param name="searchPattern"></param>
            /// <param name="searchOption"></param>
            /// <returns></returns>
            public IEnumerable<string> GetFiles(string path, string searchPattern = "*", SearchOption searchOption = SearchOption.TopDirectoryOnly)
            {
                if (path == null)
                    throw new ArgumentNullException("path");
                if (searchPattern == null)
                    throw new ArgumentNullException("searchPattern");

                if (path[path.Length - 1] != '/')
                    path += "/";

                if (zipFile != null)
                {
                    foreach (var entry in zipFile.Where(z =>
                    {
                        if (z.IsDirectory
                          || !z.FileName.StartsWith(path, StringComparison.InvariantCultureIgnoreCase)
                          || (searchOption == SearchOption.TopDirectoryOnly && z.FileName.LastIndexOf('/', path.Length) > path.Length))
                            return false;
                        int index = z.FileName.LastIndexOf('/');

                        string filename = index == -1 ? z.FileName : z.FileName.Substring(index + 1);
                        return PassesFilter(filename, searchPattern);
                    }))
                        yield return entry.FileName;
                }
            }

            private static bool PassesFilter(string filename, string searchPattern)
            {
                var sections = searchPattern.Split(new char[] { '*' }, StringSplitOptions.None);

                int currentPosition = 0;
                for (int i = 0; i < sections.Length; i++)
                {
                    var section = sections[i];
                    if (section != string.Empty)
                    {
                        int index = filename.IndexOf(section, currentPosition, StringComparison.InvariantCultureIgnoreCase);
                        if (index == -1)
                            return false;
                        else
                            currentPosition = index + section.Length;
                        if (i == sections.Length - 1)
                            return currentPosition == filename.Length;
                    }
                }
                return true;
            }
        }

        private static PakReaderHelper helper;

        /// <summary>
        /// Open a copy of the file in the pak
        /// </summary>
        /// <param name="relativePath"></param>
        /// <returns></returns>
        public static Stream OpenFile(string relativePath)
        {
            if (helper == null)
                helper = new PakReaderHelper();
            return helper.OpenFile(relativePath);
        }

         /// <summary>
        /// Get the listing of files in the pak
        /// </summary>
        /// <param name="path"></param>
        /// <param name="searchPattern"></param>
        /// <param name="searchOption"></param>
        /// <returns></returns>
        public static IEnumerable<string> GetFiles(string path, string searchPattern = "*", SearchOption searchOption = SearchOption.TopDirectoryOnly)
        {
            if (helper == null)
                helper = new PakReaderHelper();
            return helper.GetFiles(path, searchPattern, searchOption);
        }
    }
}
